package de.slothsoft.commons.swing.validation;

import java.util.ArrayList;
import java.util.List;

import javax.swing.JComponent;

import de.slothsoft.commons.swing.validation.IValidationListener.ValidationEvent;

public class Validator<S extends JComponent> {

	private List<IValidationListener> listeners = new ArrayList<IValidationListener>();
	private boolean valid = true;
	private S source;
	private List<ITester<S>> testers = new ArrayList<ITester<S>>();
	private String errorMessage;
	private String sourceName;

	public Validator(S source, String sourceName) {
		this.source = source;
		this.sourceName = sourceName;
	}

	public boolean validate() {
		boolean newValid = true;
		this.errorMessage = null;
		for (ITester<S> tester : this.testers) {
			if (!tester.acceptInput(this.source)) {
				this.errorMessage = tester.getErrorMessage(getSourceName());
				newValid = false;
				break;
			}
		}
		setValid(newValid);
		return newValid;
	}

	public String getErrorMessage() {
		return this.errorMessage;
	}

	public String getSourceName() {
		return this.sourceName;
	}

	public void addTester(ITester<S> tester) {
		this.testers.add(tester);
	}

	public void addTesters(List<ITester<S>> testers) {
		this.testers.addAll(testers);
	}

	public void removeTester(ITester<S> tester) {
		this.testers.remove(tester);
	}

	public void addListener(IValidationListener listener) {
		this.listeners.add(listener);
	}

	public void removeListener(IValidationListener listener) {
		this.listeners.remove(listener);
	}

	public void fireValidationChanged(JComponent source, boolean newValue,
			String errorMessage) {
		IValidationListener[] array = this.listeners
				.toArray(new IValidationListener[0]);
		ValidationEvent event = new ValidationEvent(source, newValue,
				errorMessage);
		for (IValidationListener l : array) {
			l.validationChanged(event);
		}
	}

	public boolean wasValid() {
		return this.valid;
	}

	public void setValid(boolean newValid) {
		boolean oldValid = this.valid;
		this.valid = newValid;
		if (oldValid != newValid) {
			fireValidationChanged(getSource(), newValid, getErrorMessage());
		}
	}

	public S getSource() {
		return this.source;
	}

}
